package com.kingbook.core.generator;

import com.kingbook.common.utils.StringUtils;
import com.kingbook.core.enums.Token;
import com.kingbook.core.exception.ParamsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.kingbook.core.enums.PrimaryKeyType.AUTO_INCREMENT;
import static com.kingbook.core.enums.PrimaryKeyType.FUNCTION;

/**
 * @Author: Bucky
 * @Date: 2019/1/2
 * @Version 1.0
 */
public class SqlConfigurationGenerator extends Generator {

    private static final Logger logger = LoggerFactory.getLogger(SqlConfigurationGenerator.class);

    private String target;

    private List<TableBean> tables;

    private String setExpression = "<when notNull=\":${var}\">\n\t\t\t\t\t${col} = :${var} , \n\t\t\t\t</when>";

    private String whenExpression = "\t\t\t<when notNull=\":${var}\">\n\t\t\t\t${col} = :${var} and \n\t\t\t</when>";

    private String trimExpression = "\t\t\t<trim prefix=\"and\" suffix=\"\" prefixOverrides=\"\" suffixesOverrides=\"and|,\">";

    private String expression = "${pk} = :${pkVar} and ";

    private AnnotationInfo info;

    SqlConfigurationGenerator() {
    }

    SqlConfigurationGenerator(String target, List<TableBean> tables, AnnotationInfo info, boolean overWrite) {
        this.tables = tables;
        this.target = target;
        this.info = info;
        setOverWrite(overWrite);
    }

    void gen() {
        String template = readTemplate("generatorSql.xml");
        String table;
        String tableVar;
        StringBuilder columns;
        StringBuilder insertColumns;
        StringBuilder insertColumnsVar;
        String insertColumnsStr;
        String insertColumnsVarStr;
        String orderBy;
        StringBuilder columnsSet;
        StringBuilder pkConditions;
        StringBuilder whereConditions;
        Set<String> colSet;
        String tTemplate;
        StringBuilder sb;
        Map<String, PrimaryKey> primaryKeyMap;
        for (TableBean bean : tables) {
            colSet = bean.getColumns().keySet();
            table = bean.getTableName();
            tableVar = bean.getObjectName();
            pkConditions = new StringBuilder();
            orderBy = "";
            primaryKeyMap = bean.getPrimaryKeys();
            for (String pk : primaryKeyMap.keySet()) {
                pkConditions.append(expression.replace("${pk}", trimKeyword(pk)).replace("${pkVar}", StringUtils.toCamelCase(pk)));
                orderBy += trimKeyword(pk) + " desc,";
            }
            orderBy = StringUtils.isNotEmpty(orderBy) ? "order by " + orderBy.substring(0, orderBy.length() - 1) : "";
            columnsSet = new StringBuilder();
            whereConditions = new StringBuilder();
            columns = new StringBuilder();
            insertColumns = new StringBuilder();
            insertColumnsVar = new StringBuilder();
            insertColumnsStr = "";
            insertColumnsVarStr = "";
            int e = colSet.size();
            boolean nullable;
            boolean beforeNull = true;
            boolean hasWhen = false;
            String var;
            String scol;
            String cache;
            for (String col : colSet) {
                var = StringUtils.toCamelCase(col);
                scol = trimKeyword(col);
                columns.append(scol);
//                if (e < colSet.size()) {
//                    columnsSet.append("            ");
//                    whereConditions.append("        ");
//                }
                if (!primaryKeyMap.containsKey(scol)) {
                    columnsSet.append("\t\t\t\t" + setExpression.replace("${col}", scol).replace("${var}", var));
                }
                whereConditions.append(whenExpression.replace("${col}", scol).replace("${var}", var));
                nullable = bean.getColumns().get(col).nullable;
                if (nullable) {
                    hasWhen = true;
                    insertColumns.append("\n\t\t\t\t\t<when notNull=\":").append(var).append("\">\n\t\t\t\t\t\t").append(scol).append(",\n\t\t\t\t\t</when>");
                    insertColumnsVar.append("\n\t\t\t\t\t<when notNull=\":").append(var).append("\">\n\t\t\t\t\t\t:").append(var).append(",\n\t\t\t\t\t</when>");
                } else {
                    String sp = "";
                    if (beforeNull)
                        sp = "\n\t\t\t\t\t";
                    if (primaryKeyMap.containsKey(scol)) {
                        if (FUNCTION.equals(primaryKeyMap.get(scol).getPrimaryKeyType())) {
                            if (StringUtils.isEmpty(primaryKeyMap.get(scol).getFunctionName()))
                                throw new ParamsException("----> 没有设置FunctionName, column=" + primaryKeyMap.get(scol).getColumn());
                            insertColumns.append(sp).append(scol).append(",");
                            insertColumnsVar.append(sp).append(primaryKeyMap.get(scol).getFunctionName()).append("()").append(",");
                        } else if (!AUTO_INCREMENT.equals(primaryKeyMap.get(scol).getPrimaryKeyType())) {
                            insertColumns.append(sp).append(scol).append(",");
                            insertColumnsVar.append(sp).append(":").append(var).append(",");
                        }
                    } else {
                        insertColumns.append(sp).append(scol).append(",");
                        insertColumnsVar.append(sp).append(":").append(var).append(",");
                    }
                }
                if (e-- > 1) {
                    columnsSet.append("\n");
                    whereConditions.append("\n");
                    columns.append(",");
                }
                beforeNull = nullable || primaryKeyMap.containsKey(scol);
            }
            if (hasWhen) {
                insertColumnsStr = insertColumns.insert(0, "<trim suffixesOverrides=\",\">").append("\n\t\t\t\t</trim>").toString();
                insertColumnsVarStr = insertColumnsVar.insert(0, "<trim suffixesOverrides=\",\">").append("\n\t\t\t\t</trim>").toString();
            }else {
                insertColumnsStr = insertColumns.toString();
                insertColumnsStr = insertColumnsStr.endsWith(",") ? insertColumnsStr.substring(7, insertColumnsStr.length() - 1) : insertColumnsStr;
                insertColumnsVarStr = insertColumnsVar.toString();
                insertColumnsVarStr = insertColumnsVarStr.endsWith(",") ? insertColumnsVarStr.substring(7, insertColumnsVarStr.length() - 1) : insertColumnsVarStr;
            }
            cache = "";
            if (bean.getCacheConfig().isUseCache())
                cache = " useCache=\"true\" cacheMaxSize=\"" + bean.getCacheConfig().getCacheMaxSize() + "\" cacheDuration=\"" + bean.getCacheConfig().getCacheDuration() + "\"";
            tTemplate = template;
            writeTemplate(target + "/" + tableVar + ".xml",
                    tTemplate.replace("${author}", info.getAuthor())
                            .replace("${time}", info.getTime())
                            .replace("${version}", info.getVersion())
                            .replace("${table}", trimKeyword(table))
                            .replace("${tableVar}", tableVar)
                            .replace("${columns}", columns)
                            .replace("${pkConditions}", pkConditions.length() > 0 ? "where " + pkConditions.substring(0, pkConditions.lastIndexOf(" and")) : "")
                            .replace("${whereConditions}", whereConditions)
                            .replace("${insertColumns}", insertColumnsStr)
                            .replace("${insertColumnsVar}", insertColumnsVarStr)
                            .replace("${columnsSet}", columnsSet)
                            .replace("${orderBy}", orderBy)
                            .replace("${cache}", cache));
        }

    }

    private String trimKeyword(String s) {
        return Token.isKeywords(s.toUpperCase()) ? "`" + s + "`" : s;
    }

}
